﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Plugin1
{

    public class ResizeBehavior : Behavior<FrameworkElement>
    {
        /// <summary>
        /// 是否启用
        /// </summary>
        public bool IsEnable { get; set; }

        /// <summary>
        /// 拖拽方向
        /// </summary>
        public ResizeDirection CurResizeDirection
        {
            get { return _curResizeDirection; }
            set { _curResizeDirection = value; }
        }
        ResizeDirection _curResizeDirection = ResizeDirection.None;




        public UIElement ResizeElement
        {
            get { return (UIElement)GetValue(ResizeElementProperty); }
            set { SetValue(ResizeElementProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ResizeElement.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ResizeElementProperty =
            DependencyProperty.Register("ResizeElement", typeof(UIElement), typeof(ResizeBehavior), new PropertyMetadata(OnResizeElementChanged));

        private static void OnResizeElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ResizeBehavior behavior = d as ResizeBehavior;

            if (behavior != null)
            {
                UIElement oldItem = e.OldValue as UIElement;
                if (oldItem != null)
                {
                    oldItem.MouseLeftButtonDown -= behavior.Resize_MouseLeftButtonDown;
                }
                UIElement newItem = e.NewValue as UIElement;
                if (newItem != null)
                {
                    newItem.MouseLeftButtonDown += behavior.Resize_MouseLeftButtonDown;
                }
            }

        }



        ///// <summary>
        ///// 拖拽控件
        ///// </summary>
        //public UIElement ResizeElement
        //{
        //    get { return _resizeElement; }
        //    set {
        //        if(_resizeElement != null)
        //            _resizeElement.MouseLeftButtonDown -= Resize_MouseLeftButtonDown;
        //        _resizeElement = value;

        //        if (_resizeElement != null)
        //            _resizeElement.MouseLeftButtonDown += Resize_MouseLeftButtonDown;
        //    }
        //}
        //UIElement _resizeElement = null;

        // 移动时最后点坐标
        private Point lastPoint;
        // 作用未知，应该和translate相关
        private double VerticalOffset = 0;
        // 作用未知，应该和translate相关
        private double HorizontalOffset = 0;

        //要缩放大小的控件
        FrameworkElement _targetElement = null;

        protected override void OnAttached()
        {
            base.OnAttached();

            _targetElement = AssociatedObject;

            if (ResizeElement != null)
            {
                ResizeElement.MouseLeftButtonDown -= Resize_MouseLeftButtonDown;
                ResizeElement.MouseLeftButtonDown += Resize_MouseLeftButtonDown;
            }
        }

      

        protected override void OnDetaching()
        {
            base.OnDetaching();
            if (ResizeElement != null)
            {
                ResizeElement.MouseLeftButtonDown -= Resize_MouseLeftButtonDown;
            }
        }


        #region 大小调整
        private void Resize_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

            if (double.IsNaN(_targetElement.ActualWidth) || double.IsNaN(_targetElement.ActualHeight) || !IsEnable)
                return;

            this.ResizeElement.CaptureMouse();

            lastPoint = e.GetPosition(_targetElement.Parent as UIElement);

            Application.Current.RootVisual.MouseMove += Resize_MouseMove;
            Application.Current.RootVisual.MouseLeftButtonUp += Resize_MouseLeftButtonUp;
            Application.Current.RootVisual.MouseLeave += Resize_MouseLeave;
            e.Handled = true;
        }
        private bool isAdjusted = false;
        private void Resize_MouseMove(object sender, MouseEventArgs e)
        {
            Point p2 = e.GetPosition(_targetElement.Parent as UIElement);
            System.Diagnostics.Debug.WriteLine(p2);

            if (double.IsNaN(_targetElement.Width))
                _targetElement.Width = _targetElement.ActualWidth;

            if (double.IsNaN(_targetElement.Height))
                _targetElement.Height = _targetElement.ActualHeight;

            if (!isAdjusted && _targetElement.Parent is Grid)
            {
                AdjustWhenGrid();
                isAdjusted = true;
            }
            if (_curResizeDirection == ResizeDirection.ResizeRight || _curResizeDirection == ResizeDirection.ResizeRDCorner || _curResizeDirection == ResizeDirection.ResizeRTCorner)
            {
                ResizebyRight(p2);
            }

            if (_curResizeDirection == ResizeDirection.ResizeLeft || _curResizeDirection == ResizeDirection.ResizeLTCorner || _curResizeDirection == ResizeDirection.ResizeLDCorner)
            {
                ResizebyLeft(p2);
            }

            if (_curResizeDirection == ResizeDirection.ResizeRDCorner || _curResizeDirection == ResizeDirection.ResizeBottom || _curResizeDirection == ResizeDirection.ResizeLDCorner)
            {
                ResizebyBottom(p2);
            }

            if (_curResizeDirection == ResizeDirection.ResizeLTCorner || _curResizeDirection == ResizeDirection.ResizeTop || _curResizeDirection == ResizeDirection.ResizeRTCorner)
            {
                ResizebyTop(p2);
            }

            lastPoint = p2;

        }

        private void AdjustWhenGrid()
        {
            Grid grid = _targetElement.Parent as Grid;
            int col = Grid.GetColumn(_targetElement);
            int row = Grid.GetRow(_targetElement);
            double left = _targetElement.Margin.Left, right = _targetElement.Margin.Right, top = _targetElement.Margin.Top, bottom = _targetElement.Margin.Bottom;
            for (int i = 0; i < col; i++)
            {
                left += grid.ColumnDefinitions[i].ActualWidth;
            }
            for (int i = col + 1; i < grid.ColumnDefinitions.Count; i++)
            {
                right += grid.ColumnDefinitions[i].ActualWidth;
            }
            for (int i = 0; i < row; i++)
            {
                top += grid.RowDefinitions[i].ActualHeight;
            }
            for (int i = row + 1; i < grid.RowDefinitions.Count; i++)
            {
                bottom += grid.RowDefinitions[i].ActualHeight;
            }

            if (Math.Abs(this.HorizontalOffset) > 0)
            {
                if (_targetElement.HorizontalAlignment == HorizontalAlignment.Stretch || _targetElement.HorizontalAlignment == HorizontalAlignment.Center)
                {
                    left = ((_targetElement.Parent as FrameworkElement).ActualWidth - _targetElement.Width + left - right) / 2;
                    right = 0;
                    _targetElement.HorizontalAlignment = HorizontalAlignment.Left;
                }
            }
            if (_targetElement.HorizontalAlignment == HorizontalAlignment.Left)
            {
                left += this.HorizontalOffset;
                right = 0;
            }
            else if (_targetElement.HorizontalAlignment == HorizontalAlignment.Right)
            {
                left = 0;
                right -= this.HorizontalOffset;
            }
            if (Math.Abs(this.VerticalOffset) > 0)
            {
                if (_targetElement.VerticalAlignment == VerticalAlignment.Stretch || _targetElement.VerticalAlignment == VerticalAlignment.Center)
                {
                    top = ((_targetElement.Parent as FrameworkElement).ActualHeight - _targetElement.Height + top - bottom) / 2;
                    bottom = 0;
                    _targetElement.VerticalAlignment = VerticalAlignment.Top;
                }
            }
            if (_targetElement.VerticalAlignment == VerticalAlignment.Top)
            {
                top += this.VerticalOffset;
                bottom = 0;
            }
            else if (_targetElement.VerticalAlignment == VerticalAlignment.Bottom)
            {
                top = 0;
                bottom -= this.VerticalOffset;
            }
            _targetElement.Margin = new Thickness(left, top, right, bottom);
            this.VerticalOffset = 0;
            this.HorizontalOffset = 0;
            Grid.SetRow(_targetElement, 0);
            Grid.SetColumn(_targetElement, 0);
            Grid.SetColumnSpan(_targetElement, (_targetElement.Parent as Grid).ColumnDefinitions.Count + 1);
            Grid.SetRowSpan(_targetElement, (_targetElement.Parent as Grid).RowDefinitions.Count + 1);
            Canvas.SetZIndex(_targetElement, 10);
        }

        private void ResizebyLeft(Point p2)
        {
            double xoffset = p2.X - lastPoint.X;

            if (p2.X < 3 || (xoffset < 0 && _targetElement.Width + 5 >= (_targetElement.Parent as FrameworkElement).ActualWidth))
                return;

            if (_targetElement.HorizontalAlignment != HorizontalAlignment.Right)
            {
                double right = 0.0;
                if (_targetElement.HorizontalAlignment == HorizontalAlignment.Stretch || _targetElement.HorizontalAlignment == HorizontalAlignment.Center)
                    right = ((_targetElement.Parent as FrameworkElement).ActualWidth - _targetElement.Width + _targetElement.Margin.Right - _targetElement.Margin.Left) / 2 - this.HorizontalOffset;
                else
                    right = (_targetElement.Parent as FrameworkElement).ActualWidth - _targetElement.Width - _targetElement.Margin.Left - this.HorizontalOffset;

                _targetElement.Margin = new Thickness(0, _targetElement.Margin.Top, right, _targetElement.Margin.Bottom);
                this.HorizontalOffset = 0;
                _targetElement.HorizontalAlignment = HorizontalAlignment.Right;
            }

            System.Diagnostics.Debug.WriteLine(xoffset);
            if (_targetElement.Width - xoffset >= _targetElement.MinWidth)
            {
                _targetElement.Width -= xoffset;

                if (_targetElement.Margin.Right - this.HorizontalOffset < 5)
                {
                    _targetElement.Margin = new Thickness(_targetElement.Margin.Left, _targetElement.Margin.Top, _targetElement.Margin.Right - this.HorizontalOffset, _targetElement.Margin.Bottom);
                    this.HorizontalOffset = 0;
                }
                if (_targetElement.Width + 5 > (_targetElement.Parent as FrameworkElement).ActualWidth)
                    _targetElement.Width = (_targetElement.Parent as FrameworkElement).ActualWidth - 5;

                System.Diagnostics.Debug.WriteLine(_targetElement.Width);
                System.Diagnostics.Debug.WriteLine(this.HorizontalOffset);
            }

        }

        private void ResizebyRight(Point p2)
        {
            double xoffset = p2.X - lastPoint.X;

            if (p2.X + 3 > (_targetElement.Parent as FrameworkElement).ActualWidth || (xoffset > 0 && _targetElement.Width + 5 >= (_targetElement.Parent as FrameworkElement).ActualWidth))
                return;

            if (_targetElement.HorizontalAlignment != HorizontalAlignment.Left)
            {
                double left = 0.0;
                if (_targetElement.HorizontalAlignment == HorizontalAlignment.Stretch || _targetElement.HorizontalAlignment == HorizontalAlignment.Center)
                    left = ((_targetElement.Parent as FrameworkElement).ActualWidth - _targetElement.Width + _targetElement.Margin.Left - _targetElement.Margin.Right) / 2 + this.HorizontalOffset;
                else
                    left = (_targetElement.Parent as FrameworkElement).ActualWidth - _targetElement.Width - _targetElement.Margin.Right + this.HorizontalOffset;
                _targetElement.Margin = new Thickness(left, _targetElement.Margin.Top, 0, _targetElement.Margin.Bottom);
                this.HorizontalOffset = 0;
                _targetElement.HorizontalAlignment = HorizontalAlignment.Left;
            }

            System.Diagnostics.Debug.WriteLine(xoffset);
            if (_targetElement.Width + xoffset >= _targetElement.MinWidth)
            {
                _targetElement.Width += xoffset;

                if (_targetElement.Margin.Left + this.HorizontalOffset < 5)
                {
                    _targetElement.Margin = new Thickness(_targetElement.Margin.Left + this.HorizontalOffset, _targetElement.Margin.Top, _targetElement.Margin.Right, _targetElement.Margin.Bottom);
                    this.HorizontalOffset = 0;
                }
                if (_targetElement.Width + 5 > (_targetElement.Parent as FrameworkElement).ActualWidth)
                    _targetElement.Width = (_targetElement.Parent as FrameworkElement).ActualWidth - 5;

                System.Diagnostics.Debug.WriteLine(_targetElement.Width);
                System.Diagnostics.Debug.WriteLine(this.HorizontalOffset);
            }

        }

        private void ResizebyTop(Point p2)
        {
            double yoffset = p2.Y - lastPoint.Y;

            if (p2.Y < 3 || (yoffset < 0 && _targetElement.Height + 5 >= (_targetElement.Parent as FrameworkElement).ActualHeight))
                return;
            if (_targetElement.VerticalAlignment != VerticalAlignment.Bottom)
            {
                double bottom = 0.0;
                if (_targetElement.VerticalAlignment == VerticalAlignment.Stretch || _targetElement.VerticalAlignment == VerticalAlignment.Center)
                    bottom = ((_targetElement.Parent as FrameworkElement).ActualHeight - _targetElement.Height + _targetElement.Margin.Bottom - _targetElement.Margin.Top) / 2 - this.VerticalOffset;
                else
                    bottom = (_targetElement.Parent as FrameworkElement).ActualHeight - _targetElement.Height - _targetElement.Margin.Top - this.VerticalOffset;

                _targetElement.Margin = new Thickness(_targetElement.Margin.Left, 0, _targetElement.Margin.Right, bottom);
                this.VerticalOffset = 0;
                _targetElement.VerticalAlignment = VerticalAlignment.Bottom;
            }

            if (_targetElement.Height - yoffset >= _targetElement.MinHeight)
            {
                _targetElement.Height -= yoffset;

                if (_targetElement.Margin.Top - this.VerticalOffset < 5)
                {
                    _targetElement.Margin = new Thickness(_targetElement.Margin.Left, _targetElement.Margin.Top, _targetElement.Margin.Right, _targetElement.Margin.Bottom - this.VerticalOffset);
                    this.VerticalOffset = 0;
                }
                if (_targetElement.Height + 5 > (_targetElement.Parent as FrameworkElement).ActualHeight)
                    _targetElement.Height = (_targetElement.Parent as FrameworkElement).ActualHeight - 5;

            }
        }

        private void ResizebyBottom(Point p2)
        {
            double yoffset = p2.Y - lastPoint.Y;

            if (p2.Y + 3 > (_targetElement.Parent as FrameworkElement).ActualHeight || (yoffset > 0 && _targetElement.Height + 5 >= (_targetElement.Parent as FrameworkElement).ActualHeight))
                return;
            if (_targetElement.VerticalAlignment != VerticalAlignment.Top)
            {
                double top = 0.0;
                if (_targetElement.VerticalAlignment == VerticalAlignment.Stretch || _targetElement.VerticalAlignment == VerticalAlignment.Center)
                    top = ((_targetElement.Parent as FrameworkElement).ActualHeight - _targetElement.Height + _targetElement.Margin.Top - _targetElement.Margin.Bottom) / 2 + this.VerticalOffset;
                else
                    top = (_targetElement.Parent as FrameworkElement).ActualHeight - _targetElement.Height - _targetElement.Margin.Bottom + this.VerticalOffset;

                _targetElement.Margin = new Thickness(_targetElement.Margin.Left, top, _targetElement.Margin.Right, 0);
                this.VerticalOffset = 0;
                _targetElement.VerticalAlignment = VerticalAlignment.Top;
            }

            if (_targetElement.Height + yoffset >= _targetElement.MinHeight)
            {
                _targetElement.Height += yoffset;

                if (_targetElement.Margin.Top + this.VerticalOffset < 5)
                {
                    _targetElement.Margin = new Thickness(_targetElement.Margin.Left, _targetElement.Margin.Top + this.VerticalOffset, _targetElement.Margin.Right, _targetElement.Margin.Bottom);
                    this.VerticalOffset = 0;
                }
                if (_targetElement.Height + 5 > (_targetElement.Parent as FrameworkElement).ActualHeight)
                    _targetElement.Height = (_targetElement.Parent as FrameworkElement).ActualHeight - 5;

            }
        }

        private void Resize_MouseLeave(object sender, MouseEventArgs e)
        {
            ResizeElement.ReleaseMouseCapture();

            StopResize();
        }
        private void Resize_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ResizeElement.ReleaseMouseCapture();

            StopResize();
        }

        private void StopResize()
        {
            Application.Current.RootVisual.MouseMove -= Resize_MouseMove;
            Application.Current.RootVisual.MouseLeftButtonUp -= Resize_MouseLeftButtonUp;
            Application.Current.RootVisual.MouseLeave -= Resize_MouseLeave;
        }

        #endregion

    }


 
}
